package com.apicloud.modulefloatwebview;

import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

import com.uzmap.pkg.uzcore.uzmodule.UZModuleContext;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;


public class FloatWebView {
    //状态
    public boolean status=false; //悬浮窗的专题，是否加入到窗口
    public boolean needStickSide=false; //是否需要粘贴到屏幕边缘
    public boolean needFollowTouch=false; //是否需要跟随触摸移动
    public static boolean isPortrait=true;//是否为竖屏
    public static boolean openService=false;//是否开启服务
    //静态公用缓存
    public static Map<String, FloatWebView> windowList = new HashMap<>();//用于存储已经打开的悬浮窗口列表
    //缓存
    public FloatWebView _this;
    public String _thisName;
    public Context mContext;
    public UZModuleContext moduleContext;
    public WebView webView;
    private View view;
    public WindowManager windowManager;
    public WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
    public DisplayMetrics displayMetrics = new DisplayMetrics();
    public Handler mHandler = new Handler(Looper.getMainLooper()){
        public void handleMessage(Message msg){
            int what = msg.what;
            JSONObject data = (JSONObject)msg.obj;
            switch (what) {
                case 0://remove
                    remove();
                    mHandler.removeCallbacksAndMessages(null);
                    break;
                case 1://show
                    show();
                    break;
                case 2://hide
                    hide();
                    break;
                case 3://offset
                    offsetXY(data.optInt("x",0),data.optInt("y",0));
                    break;
                case 4://size
                    viewSize(data.optInt("w",0),data.optInt("h",0));
                    break;
                case 5://noTouch
                    noTouch(data.optBoolean("noTouch",false));
                    break;
                case 6://noLimit
                    noLimit(data.optBoolean("noLimit",false));
                    break;
                case 7://center
                    center(data.optBoolean("center",false));
                    break;
                case 8://canFocus
                    canFocus(data.optBoolean("canFocus",false));
                    break;
                case 9://followTouch
                    followTouch(data.optBoolean("followTouch",false));
                    break;
                case 10://stickSide
                    stickSide(data.optBoolean("stickSide",false));
                    break;
                case 11://event
                    JSONObject ret = new JSONObject();
                    String eventName = data.optString("eventName",null);
                    if (eventName==null) break;
                    try {
                        ret.put("status",true);
                        ret.put("msg","event");
                        ret.put("eventName",eventName);
                        ret.put("data",data.optJSONObject("data"));
                        moduleContext.success(ret,false);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    };
    //内部类
    private class WebViewJsInterface{
        @JavascriptInterface
        public void remove(String jsonStr) throws JSONException{
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                handler.sendEmptyMessage(0);
            }
        }
        @JavascriptInterface
        public void show(String jsonStr) throws JSONException{
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                handler.sendEmptyMessage(1);
            }
        }
        @JavascriptInterface
        public void hide(String jsonStr) throws JSONException{
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                handler.sendEmptyMessage(2);
            }
        }
        @JavascriptInterface
        public void offset(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=3;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void size(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=4;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void noTouch(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=5;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void noLimit(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=6;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void center(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Log.e("center","center");
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=7;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void canFocus(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=8;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void followTouch(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=9;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void stickSide(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=10;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
        @JavascriptInterface
        public void event(String jsonStr) throws JSONException {
            JSONObject data = new JSONObject(jsonStr);
            String name = data.optString("name");
            if (windowList.containsKey(name)){
                Handler handler = windowList.get(name).mHandler;
                Message msg = new Message();
                msg.what=11;
                msg.obj = data;
                handler.sendMessage(msg);
            }
        }
    }
    /**
     * 悬浮窗构造类，
     */
    public FloatWebView(Context context, UZModuleContext mct, String name, String url) {
        _this = this;
        _thisName = name;
        mContext = context;
        moduleContext = mct;
        //创建窗口
        webView = new WebView(mContext);
        webView.loadUrl(url);
        webView.getSettings().setJavaScriptEnabled(true);//支持js
        webView.getSettings().setDatabaseEnabled(true);
        webView.getSettings().setDefaultTextEncodingName("utf-8");
        //允许本地存储
        webView.getSettings().setDomStorageEnabled(true);
        webView.getSettings().setAllowFileAccess(true);
        webView.getSettings().setAppCacheEnabled(true);
        //背景颜色透明
        webView.setBackgroundColor(0);
        Drawable drawable = webView.getBackground();
        if(drawable!=null){
            drawable.setAlpha(0);
        }
        webView.addJavascriptInterface(new WebViewJsInterface(),"floatWebView");
        webView.setWebViewClient(new WebViewClient(){
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                if(Build.VERSION.SDK_INT >= 24) view.loadUrl(String.valueOf(request.getUrl()));
                return true;
            }
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });
        webView.setWebChromeClient(new WebChromeClient(){});
        view = (View)webView;
        //获取窗口管理WindowManager
        windowManager = (WindowManager) mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        //设置默认WindowManager.LayoutParams
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            //刘海屏延伸到刘海里面
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;
        } else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        layoutParams.packageName = mContext.getPackageName();

        layoutParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED //开启硬件加速
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL //不接收窗口外的点触事件
                |WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //不许获得焦点
                |WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN //全屏的时候，使用沉浸模式，覆盖状态栏
        ;
        //默认不全屏
        layoutParams.width = (int)(displayMetrics.widthPixels*0.6);
        layoutParams.height = (int)(displayMetrics.heightPixels*0.6);
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;//默认以左上角为原点
        layoutParams.format = PixelFormat.TRANSPARENT;//视图格式为可透明
        //触摸拖动
        view.setOnTouchListener(new View.OnTouchListener() {
            private int downX = 0;
            private int downY = 0;
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (!needFollowTouch) return false;
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        downX = (int) event.getRawX();
                        downY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int nowX = (int) event.getRawX();
                        int nowY = (int) event.getRawY();
                        layoutParams.x += (nowX - downX);
                        layoutParams.y += (nowY - downY);
                        if (status)windowManager.updateViewLayout(view, layoutParams);
                        downX = nowX;
                        downY = nowY;
                        break;
                    case MotionEvent.ACTION_UP:
                        if(needStickSide) stickSideAction();
                        break;
                    default:
                        break;
                }
                return false;
            }
        });
        try {
            if (windowList.containsKey(name))windowList.get(name).remove();
            windowManager.addView(view, layoutParams);
            windowList.put(name,this);
            status = true;
            if (!openService && mContext instanceof Activity){
                Intent intent = new Intent(mContext, FloatWebViewService.class);
                mContext.startService(intent);
                openService=true;
            }
        } catch (Exception e) {
            Toast.makeText(mContext, "添加悬浮窗失败！！！！！！请检查悬浮窗权限", Toast.LENGTH_SHORT).show();
        }
    }
    //-----------------------参数配置系列方法-------------------------
    /**
     * 悬浮窗位置偏移
     */
    public FloatWebView offsetXY(int x, int y){
        layoutParams.x = x;
        layoutParams.y = y;
        if (status)windowManager.updateViewLayout(view, layoutParams);
        return this;
    }
    /**
     * 悬浮窗大小
     */
    public FloatWebView viewSize(int width, int height){
        layoutParams.width = width;
        layoutParams.height = height;
        if (status)windowManager.updateViewLayout(view, layoutParams);
        return this;
    }
    public FloatWebView noLimit(boolean tf){
        if (tf){
            layoutParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        }else{
            layoutParams.flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        }
        if (status)windowManager.updateViewLayout(view, layoutParams);
        return this;
    }

    /**
     * 设置定位坐标原点是否为中心
     */
    public FloatWebView center(boolean tf){
        if (tf){
            layoutParams.gravity = Gravity.CENTER;
            layoutParams.x = 0;
            layoutParams.y = 0;
        }else{
            layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        }
        if (status)windowManager.updateViewLayout(view, layoutParams);
        return this;
    }
    /**
     * 悬浮窗无法触摸
     */
    public FloatWebView noTouch(boolean tf){
        if (tf){
            layoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
        }else {
            layoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
        }
        if (status)windowManager.updateViewLayout(view, layoutParams);
        return this;
    }
    /**
     * 窗口获取焦点。
     * 通常获取焦点后，悬浮窗可以和软键盘发生交互，但被覆盖的应用会失去焦点，具体表现例如：游戏将失去背景音乐
     */
    public FloatWebView canFocus(boolean tf){
        if (tf){
            layoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        }else{
            layoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        }
        if (status)windowManager.updateViewLayout(view, layoutParams);
        return this;
    }
    /**
     * 绑定触摸事件，悬浮窗跟随
     */
    public FloatWebView followTouch(boolean tf){
        needFollowTouch = tf;
        return this;
    }
    /**
     * 粘贴到屏幕边缘
     */
    public FloatWebView stickSide(boolean tf){
        needStickSide=tf;
        if(tf)stickSideAction();
        return this;
    }
    private void stickSideAction(){
        int mw = view.getWidth();
        int vw = isPortrait ? displayMetrics.widthPixels : displayMetrics.heightPixels;
        int startx = layoutParams.x;
        int endx=0;
        if (layoutParams.gravity == Gravity.CENTER){
            endx = (int)(startx <=0 ? (mw-vw)*0.5 : (vw-mw)*0.5);
        }else{
            endx = (int)(startx <= (vw-mw)*0.5 ? 0 : vw-mw);
        }
        ValueAnimator valueAnimator = ValueAnimator.ofInt(startx, endx);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (status) {
                    int v = (int)animation.getAnimatedValue();
                    layoutParams.x = v;
                    windowManager.updateViewLayout(view, layoutParams);
                }
            }
        });
        valueAnimator.setDuration(300);
        valueAnimator.start();
    }
    //-----------------------操作系列方法-------------------------
    /**
     * 显示悬浮窗，如果还没有生成就生成
     */
    public FloatWebView show() {
        view.setVisibility(View.VISIBLE);
        return this;
    }
    /**
     * 隐藏悬浮窗，以View.INVISIBLE的方式
     */
    public FloatWebView hide() {
        view.setVisibility(View.INVISIBLE);
        return this;
    }
    /**
     * 移除悬浮窗
     */
    public FloatWebView remove() {
        status=false;
        windowManager.removeView(view);
        windowList.remove(_thisName);
        if (windowList.size()==0 && openService && mContext instanceof Activity){
            Intent intent = new Intent(mContext, FloatWebViewService.class);
            mContext.stopService(intent);
            openService=false;
        }
        //移除所有的通知消息
        mHandler.removeCallbacksAndMessages(null);
        return this;
    }
    //-------------------------------工具系列方法-----------------------------
    /**
     * 判断悬浮窗是否显示的状态
     */
    public boolean isShow() {
        return (view.getVisibility() == View.VISIBLE);
    }
}
